import PySimpleGUI as sg

import os, sys, time, datetime, calendar, tkinter, hashlib, psutil

from sg_3 import sys_gui

from sg_4 import pwd_gui


def main_gui():  # 程序主界面
    frame_layout_time = [[sg.Button('时间工具', key='timeChange')]]
    frame_layout_md5 = [[sg.Button('加密工具', key='md5')]]
    frame_layout_file = [[sg.Button('文件查询', key='file_search')]]
    frame_layout_sys = [[sg.Button('系统信息', key='sys_info')]]
    frame_layout_pwd = [[sg.Button('密码生成', key='sys_pwd')]]
    sg.theme('LightBlue3')
    layout = [[sg.Text('Moc工具箱')],
              [sg.Frame(layout=frame_layout_time, title='时间工具', relief=sg.RELIEF_SUNKEN),
               sg.Frame(layout=frame_layout_md5, title='加密工具', relief=sg.RELIEF_SUNKEN)],
              [sg.Frame(layout=frame_layout_file, title='文件查询', relief=sg.RELIEF_SUNKEN),
               sg.Frame(layout=frame_layout_sys, title='系统信息', relief=sg.RELIEF_SUNKEN)],
              [sg.Frame(layout=frame_layout_pwd, title='密码生成', relief=sg.RELIEF_SUNKEN)],
              [sg.Button('退出')]]

    win_main = sg.Window('Moc工具箱', layout, font=("宋体", 15), default_element_size=(100, 1))

    while True:
        ev_main, vals_main = win_main.Read()
        if ev_main in (None, '退出'):
            break
        if ev_main == 'timeChange':
            sg.theme('LightBlue3')
            timeTools_gui(win_main)
        if ev_main == 'md5':
            sg.theme('LightBlue3')
            enp_gui(win_main)
        if ev_main == 'file_search':
            sg.theme('LightBlue3')
            fileSearcher_gui(win_main)
        if ev_main == 'sys_info':
            sg.theme('LightBlue3')
            sys_gui(win_main)
        if ev_main == 'sys_pwd':
            sg.theme('DarkBlue3')
            pwd_gui(win_main)
    win_main.close()


def fileSearcher_gui(win_main):
    win_main.Hide()
    table_data = []
    table_header = ['文件名' + " " * 15, '路径' + " " * 50]
    layout_file = [[sg.Text('选择文件路径：', font=("宋体", 10)), sg.FolderBrowse('打开文件夹', key='folder', target='file_folder')],
                   [sg.Text('你选择的文件夹是：', font=("宋体", 10)),
                    sg.Input('', font=("宋体", 10), key='file_folder')],
                   [sg.Text('输入文件名称查询：', font=("宋体", 10)), sg.InputText(size=(50, 5), key='file_name', font=("宋体", 10)),
                    sg.Button('查询', key='file_searcher')],
                   [sg.Table([[" " * 160, " " * 160]], headings=table_header, justification='left', key='result_search',
                             auto_size_columns=True, font=("宋体", 10))],
                   [sg.Button('返回', key='back_file', font=("宋体", 13))]
                   ]
    win_file = sg.Window('文件查询', layout_file, font=("宋体", 15), default_element_size=(50, 1))

    while True:
        ev_file, vals_file = win_file.Read()
        if ev_file is None or ev_file == 'back_file':
            win_file.close()
            win_main.UnHide()
            break
        if ev_file == 'file_searcher':
            if os.path.exists(vals_file['file_folder']) == True and vals_file['file_name']:
                search_result = file_search(vals_file['file_folder'], vals_file['file_name'])
                print("{0}文件名查询结果如下{0}".format('*' * 10))
                table_data = [[v, k] for k, v in search_result.items()]
            # if search_result != {}:
            # for k, v in search_result.items():
            # print(f"文件名：{v},文件所在路径：{k}")
            # else:
            # print('查询结果为空')
            else:
                # print('搜索文件名或查询文件夹异常，请检查')
                pass
            win_file['result_search'].update(table_data)


def enp_gui(win_main):
    win_main.Hide()
    layout_file = [
        [sg.Text('文件转MD5：', font=("宋体", 10)),
         sg.FileBrowse('打开文件', key='fileBrowser', target='md5_text1', font=("宋体", 10)),
         sg.Button('go', key='get_md5ByFiles', font=("宋体", 10))],
        [sg.Text('你选择的文件夹是:', font=("宋体", 10)),
         sg.InputText('', key='md5_text1', size=(60, 1), font=("宋体", 10), tooltip='file_path')]]
    layout_enp = [[sg.Text('加密前：', font=("宋体", 10)), sg.InputText('', font=("宋体", 10), key='enr_bef')],
                  [sg.Text('加密方式：', font=("宋体", 10)),
                   sg.Combo(('MD5', 'SHA1', 'SHA256', 'SHA512'), default_value='MD5', size=(40, 5), key='choose_enp',
                            font=("宋体", 10), enable_events=True),
                   sg.Button('go', key='enp_way', font=("宋体", 10))],
                  [sg.Column(layout=layout_file, key='is_visible', visible=True)],
                  # [sg.Output(size=(70, 20), font=("宋体", 10), key='md5_output')],
                  [sg.Text('加密后：', font=("宋体", 10)), sg.Multiline('', font=("宋体", 10), key='enr_aft', size=(80, 4))],
                  [sg.Button('返回', key='back_enp', font=("宋体", 15)),
                   sg.Button('清空', key='clear_value', font=("宋体", 15))]
                  ]

    win_enp = sg.Window('加密工具', layout_enp, font=("宋体", 15), default_element_size=(50, 1))

    while True:
        ev_enp, vals_enp = win_enp.Read()
        if ev_enp is None or ev_enp == 'back_enp':
            win_enp.close()
            win_main.UnHide()
            # sys.modules.pop('md5') # 释放已导入模块
            break
        if ev_enp == 'clear_value':  # 清空输入
            for key in vals_enp:
                if key not in ('fileBrowser', 'choose_enp'):
                    win_enp[key].update('')

        if ev_enp == 'choose_enp':
            win_enp['enr_aft'].update('')  # 切换时清空生成的加密
        if vals_enp['choose_enp'] == 'MD5':  # 控制md5文件部分隐藏/显示
            win_enp['is_visible'].update(visible=True)
        else:
            win_enp['is_visible'].Update(visible=False)

        if ev_enp == 'enp_way':
            result = get_value(vals_enp['enr_bef'], vals_enp['choose_enp'])
            win_enp['enr_aft'].update(value=result)

        if ev_enp == 'get_md5ByFiles':
            file_path = vals_enp['fileBrowser']
            file_md5 = file_to_md5(file_path)
            win_enp['enr_aft'].update(value=file_md5)


def timeTools_gui(win_main):
    win_main.Hide()  # 隐藏win_main
    layout_1 = [[sg.Text('周一：', font=("宋体", 10)), sg.InputText('', key='monday', size=(15, 20), font=("宋体", 15)),
                 sg.Text('周日：', font=("宋体", 10)), sg.InputText('', key='sunday', size=(15, 20), font=("宋体", 15))]]
    layout_2 = [[sg.Text('第一天：', font=("宋体", 10)), sg.InputText('', key='firstDay', size=(15, 20), font=("宋体", 15)),
                 sg.Text('最后一天：', font=("宋体", 10)), sg.InputText('', key='lastDay', size=(15, 20), font=("宋体", 15))]]
    layout_timeChange = [[sg.Text('获取当前时间戳', font=("宋体", 10)), sg.Button('>>', key='get_timeStamp')],
                         [sg.Text('10位(秒)：', font=("宋体", 10)),
                          sg.InputText('', key='get_timeStamp_byNow_10', size=(15, 20), font=("宋体", 15)),
                          sg.Text('13位(毫秒)：', font=("宋体", 10)),
                          sg.InputText('', key='get_timeStamp_byNow_13', size=(15, 20), font=("宋体", 15))],
                         [sg.Text('获取当前时间字符串:', font=("宋体", 10)),
                          sg.InputText('', key='get_timeStr_byNow', size=(20, 40), font=("宋体", 10)),
                          sg.Button('>>', key='get_timeStr')],
                         [sg.Text('时间戳转字符串:', font=("宋体", 10)),
                          sg.InputText('', size=(15, 20), key='inputTime', font=("宋体", 15)),
                          sg.Button(">>", key='stamp_change_str'),
                          sg.InputText('', key='timeStamp_to_str', size=(20, 40), font=("宋体", 10))],
                         [sg.Text('获取指定时间戳：', font=("宋体", 10)),
                          sg.CalendarButton('选择日期', font=("宋体", 10), target='choose_date')],
                         [sg.InputText('', key='choose_date', font=("宋体", 10), size=(20, 40)),
                          sg.Button('>>', key='date_to_stamp'),
                          sg.InputText('', key='-STAMP-', font=("宋体", 15), size=(15, 20))],
                         [sg.Text('其他:', font=("宋体", 10)),
                          sg.Combo(['当前周周一和周日时间戳', '前n个月的第一天和最后一天时间戳'], key='complex', font=("宋体", 10),
                                   default_value='当前周周一和周日时间戳', size=(50, 1),
                                   enable_events=True),
                          sg.Spin([i for i in range(1, 13)], initial_value=1, key='month_range', visible=False,
                                  size=(2, 2)),
                          sg.Button('>>', key='get_complex')],
                         [sg.Column(layout=layout_1, key='1_is_visible', visible=True)],
                         [sg.Column(layout=layout_2, key='2_is_visible', visible=False)],
                         [sg.Button('返回工具箱', key='back_timeChange', font=("宋体", 13))]
                         ]

    win_mr = sg.Window('Time Tools~', layout_timeChange, font=("宋体", 15), default_element_size=(50, 1))

    while True:
        ev_mr, vals_mr = win_mr.Read()
        if ev_mr is None or ev_mr == 'back_timeChange':
            win_mr.close()
            win_main.UnHide()
            # sys.modules.pop('timeChange') # 释放已导入模块
            break

        if ev_mr == 'get_timeStamp':
            win_mr['get_timeStamp_byNow_10'].update(value=int(time.time()))
            win_mr['get_timeStamp_byNow_13'].update(value=int(time.time() * 1000))

        if ev_mr == 'complex':  # 控件显隐控制
            if vals_mr['complex'] == '前n个月的第一天和最后一天时间戳':
                win_mr['month_range'].Update(visible=True)
                win_mr['1_is_visible'].update(visible=False)
                win_mr['2_is_visible'].update(visible=True)
        else:
            win_mr['month_range'].Update(visible=False)
            win_mr['1_is_visible'].update(visible=True)
            win_mr['2_is_visible'].update(visible=False)

        if ev_mr == 'date_to_stamp':
            win_mr['-STAMP-'].update(value=str_to_timeStamp(vals_mr['choose_date']))

        if ev_mr == 'stamp_change_str':
            if vals_mr['inputTime']:
                time_con = vals_mr['inputTime']
                changedTime = time_change(int(time_con))

        if changedTime:
            win_mr['timeStamp_to_str'].update(value=changedTime)
        else:
            pass

        if ev_mr == 'get_timeStr':
            win_mr['get_timeStr_byNow'].update(value=stampToStr(int(time.time())))
        if ev_mr == 'get_complex':
            if vals_mr['complex'] == '当前周周一和周日时间戳':
                alarm_time_monday, alarm_time_sunday = get_current_byWeek()
                win_mr['monday'].update(value=alarm_time_monday)
                win_mr['sunday'].update(value=alarm_time_sunday)
            elif vals_mr['complex'] == '前n个月的第一天和最后一天时间戳':
                alarm_time_start, alarm_time_end = get_timeStamp_byLastMonths(vals_mr['month_range'])
                win_mr['firstDay'].update(value=alarm_time_start)
                win_mr['lastDay'].update(value=alarm_time_end)


def time_change(strTime):
    if len(str(strTime)) >= 13:
        strTime = int(strTime / 1000)
    try:
        dateArray = datetime.datetime.fromtimestamp(strTime)
        timeStyle = dateArray.strftime('%Y-%m-%d %H:%M:%S')
        return timeStyle
    except:
        print('输入异常')


def stampToStr(timeStamp):
    timeArray = datetime.datetime.fromtimestamp(timeStamp)
    timeStyle = timeArray.strftime("%Y-%m-%d %H:%M:%S")
    return timeStyle


def str_to_timeStamp(strTime):
    timeArray = time.strptime(strTime, "%Y-%m-%d %H:%M:%S")
    timeStamp = int(time.mktime(timeArray))
    return timeStamp


def get_current_byWeek():
    """获取当前周周一和周日时间戳"""
    monday_array, sunday_array = datetime.date.today(), datetime.date.today()
    one_day = datetime.timedelta(days=1)
    while monday_array.weekday() != 0:  # 获取周一
        monday_array -= one_day
    while sunday_array.weekday() != 6:  # 获取周日
        sunday_array += one_day
    monday = monday_array.strftime("%Y-%m-%d") + " 00:00:00"  # 字符串时间
    sunday = sunday_array.strftime("%Y-%m-%d") + " 23:59:59"
    monday_timeArray = time.strptime(monday, "%Y-%m-%d %H:%M:%S")  # 转化为时间数组
    sunday_timeArray = time.strptime(sunday, "%Y-%m-%d %H:%M:%S")
    alarm_time_monday = int(time.mktime(monday_timeArray) * 1000)  # 转为时间戳
    alarm_time_sunday = int(time.mktime(sunday_timeArray) * 1000)
    return alarm_time_monday, alarm_time_sunday


def get_timeStamp_byLastMonths(n: int):
    """获取前n个月的第一天和最后一天时间字符戳"""
    year = datetime.datetime.now().year
    month = datetime.datetime.now().month
    last_months = 1
    if 0 < n <= 12:
        if month <= n:
            last_months = 12 - n + month
            year -= 1
        else:
            last_months = month - n
    else:
        print("超出输入范围（1~12）")
    end = calendar.monthrange(int(year), int(last_months))[1]
    start_date = f"{year}-{last_months}-01 00:00:00"  # 字符串时间
    end_date = f"{year}-{last_months}-{end} 23:59:59"
    print(start_date, end_date)
    start_timeArray = time.strptime(start_date, "%Y-%m-%d %H:%M:%S")  # 转化为时间数组
    end_timeArray = time.strptime(end_date, "%Y-%m-%d %H:%M:%S")
    alarm_time_end = int(time.mktime(end_timeArray) * 1000)  # 转为时间戳
    alarm_time_start = int(time.mktime(start_timeArray) * 1000)
    return alarm_time_start, alarm_time_end


def str_to_enp(str_value: str, fun):
    src = str_value.encode('utf-8')
    if src:
        try:
            my = fun
            my.update(src)
            return my.hexdigest()
        except:
            print('转换失败')


def get_value(str_value, win_value):
    if win_value == 'MD5':
        return str_to_enp(str_value, hashlib.md5())
    if win_value == 'SHA1':
        return str_to_enp(str_value, hashlib.sha1())
    if win_value == 'SHA256':
        return str_to_enp(str_value, hashlib.sha256())
    if win_value == 'SHA512':
        return str_to_enp(str_value, hashlib.sha512())


def file_to_md5(path):
    with open(path, 'rb') as fp:
        data = fp.read()
        file_md5 = hashlib.md5(data).hexdigest()
    return file_md5


def file_search(file_dir, file_name) -> dict:
    filesDict = dict()  # 存放全部文件和路径信息
    fileResult = dict()  # 存放指定的文件和路径信息
    print("{0}查询中{0}".format('*' * 10))
    for root, dirs, files in os.walk(file_dir):
        filesDict[root] = files
        for k, v in filesDict.items():
            for name in v:
                if file_name in name:
                    fileResult[k] = name
                    return fileResult  # {file_path:file_name,...}

if __name__ == '__main__':
    main_gui()
